容器化部署的意义
微服务项目通常采用容器化方式进行部署。容器化的核心价值在于:
- 环境一致性 -- 开发、测试、生产环境完全一致
- 快速部署 -- 镜像构建一次,到处运行
- 资源隔离 -- 每个服务运行在独立的容器中,互不干扰
- 弹性伸缩 -- 配合 K8s 可以方便地进行水平扩展
Dockerfile 多阶段构建
NestJS 微服务项目的 Dockerfile 采用多阶段构建(Multi-stage Build),将构建依赖和运行时依赖分离,最终生成一个精简的生产镜像。
# ---- 阶段 1: 构建依赖安装 ----
FROM node:20-alpine AS build-deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
COPY . .
# ---- 阶段 2: 构建 ----
FROM build-deps AS builder
RUN pnpm build
# ---- 阶段 3: 生产依赖安装 ----
FROM node:20-alpine AS prod-deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --prod --frozen-lockfile
# ---- 阶段 4: 最终运行镜像 ----
FROM node:20-alpine AS runner
WORKDIR /app
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package.json ./
# 安全:使用非 root 用户运行
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]
dockerfile
多阶段构建的关键点:
| 阶段 | 作用 | 镜像大小影响 |
|---|---|---|
| build-deps | 安装完整依赖(包含 devDependencies) | 不包含在最终镜像中 |
| builder | 执行 pnpm build 生成 dist 目录 | 不包含在最终镜像中 |
| prod-deps | 只安装生产依赖 | 只包含必要的 node_modules |
| runner | 最终镜像,只包含 dist 和生产依赖 | 最小化 |
使用 node:20-alpine 作为基础镜像而非 node:20,Alpine 版本体积约 50MB,而标准版约 350MB。
Docker Compose 编排微服务
在 Monorepo 项目中,使用 Docker Compose 来编排多个微服务:
# docker-compose.yml
version: '3.8'
services:
# 主服务(微服务服务端)
main:
build:
context: .
dockerfile: apps/main/Dockerfile
ports:
- "3000:3000"
restart: always
environment:
- NODE_ENV=production
- REDIS_HOST=redis
depends_on:
- redis
networks:
- microservice-network
# 客户端服务(微服务客户端 + HTTP 接口)
client:
build:
context: .
dockerfile: apps/client/Dockerfile
ports:
- "3001:3001"
restart: always
environment:
- NODE_ENV=production
depends_on:
- main
networks:
- microservice-network
# Redis(用于缓存和发布/订阅)
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- microservice-network
networks:
microservice-network:
driver: bridge
volumes:
redis-data:
yaml
Docker Compose 关键配置说明
restart: always-- 容器异常退出时自动重启depends_on-- 定义服务启动顺序,但只等待容器启动,不等待服务就绪networks-- 所有服务加入同一网络,可以通过服务名互相访问volumes-- 持久化 Redis 数据,避免容器重启后数据丢失
.dockerignore 文件
node_modules
dist
.git
.gitignore
.env
.env.*
*.md
.vscode
.idea
coverage
text
.dockerignore 防止不必要的文件被复制到 Docker 镜像中,加快构建速度并减小镜像体积。
构建和部署命令
# 构建所有服务
docker-compose build
# 启动所有服务(后台运行)
docker-compose up -d
# 查看运行状态
docker-compose ps
# 查看日志
docker-compose logs -f main
docker-compose logs -f client
# 停止所有服务
docker-compose down
# 停止并删除数据卷
docker-compose down -v
bash
生产环境部署建议
| 方面 | 建议 |
|---|---|
| 基础镜像 | 使用 alpine 或 slim 版本,减小攻击面 |
| 运行用户 | 使用非 root 用户(USER node) |
| 环境变量 | 敏感信息使用 K8s Secret 或 Docker Secrets |
| 健康检查 | 添加 HEALTHCHECK 指令或 K8s liveness probe |
| 日志 | 使用标准输出,由 K8s 统一收集 |
| 构建缓存 | 合理安排 Dockerfile 指令顺序,利用层缓存 |
↑